﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Markup;

namespace Sakura.Silverlight.Extensions
{
	/// <summary>
	/// 表示可以编辑内容的组合框。
	/// </summary>
	[TemplatePart(Name = "EditTextBox", Type = typeof(TextBox))]
	[TemplatePart(Name = "ContentPresenter", Type = typeof(ContentPresenter))]
	[StyleTypedProperty(Property = "EditTextBoxStyle", StyleTargetType = typeof(TextBox))]
	[TemplateVisualState(GroupName = "CommonStates", Name = "Normal")]
	[TemplateVisualState(GroupName = "CommonStates", Name = "MouseOver")]
	[TemplateVisualState(GroupName = "CommonStates", Name = "Disabled")]
	[TemplateVisualState(GroupName = "FocusStates", Name = "Focused")]
	[TemplateVisualState(GroupName = "FocusStates", Name = "Unfocused")]
	[TemplateVisualState(GroupName = "FocusStates", Name = "FocusedDropDown")]
	[TemplateVisualState(GroupName = "ValidationStates", Name = "Valid")]
	[TemplateVisualState(GroupName = "ValidationStates", Name = "InvalidUnfocused")]
	[TemplateVisualState(GroupName = "ValidationStates", Name = "InvalidFocused")]
	[TemplateVisualState(GroupName = "EditState", Name = "Editable")]
	[TemplateVisualState(GroupName = "EditState", Name = "NonEditable")]
	[TemplateVisualState(GroupName = "ReadOnlyState", Name = "ReadOnly")]
	[TemplateVisualState(GroupName = "ReadOnlyState", Name = "NonReadOnly")]
	[ContentProperty("ItemsSource")]
	public class EditableComboBox : ComboBox
	{
		/// <summary>
		/// 初始化一个组合框的新实例。
		/// </summary>
		public EditableComboBox()
		{
			this.DefaultStyleKey = typeof(EditableComboBox);
		}

		#region 功能属性

		/// <summary>
		/// 获取或设置一个值，指示编辑框是否只读。
		/// </summary>
		public bool IsReadOnly
		{
			get
			{
				return (bool)GetValue(IsReadOnlyProperty);
			}
			set
			{
				SetValue(IsReadOnlyProperty, value);
			}
		}

		/// <summary>
		/// 标识 <see cref="IsReadOnly" /> 依赖项属性。
		/// </summary>
		public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(EditableComboBox), new PropertyMetadata(false, IsReadOnlyChangedCallback));

		/// <summary>
		/// 当 <see cref="IsReadOnly" /> 属性更改时引发的回调。
		/// </summary>
		/// <param name="d">引发事件的对象。</param>
		/// <param name="e">事件包含的参数。</param>
		private static void IsReadOnlyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			// 代码段自动生成的局部变量。
			var target = (EditableComboBox)d;
			var oldValue = (bool)e.OldValue;
			var newValue = (bool)e.NewValue;

			if (oldValue != newValue)
			{
				target.SyncIsReadOnly();
				target.UpdateReadState();
			}
		}

		/// <summary>
		/// 获取或设置一个值，指示组合框是否处于编辑模式。
		/// </summary>
		public new bool IsEditable
		{
			get
			{
				return (bool)GetValue(IsEditableProperty);
			}
			set
			{
				SetValue(IsEditableProperty, value);
			}
		}

		/// <summary>
		/// 标识 <see cref="IsEditable" /> 依赖项属性。
		/// </summary>
		public static readonly DependencyProperty IsEditableProperty = DependencyProperty.Register("IsEditable", typeof(bool), typeof(EditableComboBox), new PropertyMetadata(false, IsEditableChangedCallback));

		/// <summary>
		/// 当 <see cref="IsEditable" /> 属性更改时引发的回调。
		/// </summary>
		/// <param name="d">引发事件的对象。</param>
		/// <param name="e">事件包含的参数。</param>
		private static void IsEditableChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			// 代码段自动生成的局部变量。
			var target = (EditableComboBox)d;
			var oldValue = (bool)e.OldValue;
			var newValue = (bool)e.NewValue;

			if (oldValue != newValue)
			{
				target.SyncIsEditable();
				target.UpdateEditState();
			}
		}

		/// <summary>
		/// 获取或设置在文本编辑框中显示的文本。
		/// </summary>
		public string Text
		{
			get
			{
				return (string)GetValue(TextProperty);
			}
			set
			{
				SetValue(TextProperty, value);
			}
		}

		/// <summary>
		/// 标识 <see cref="Text" /> 依赖项属性。
		/// </summary>
		public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(EditableComboBox), new PropertyMetadata(null, TextChangedCallback));

		/// <summary>
		/// 当 <see cref="Text" /> 属性更改时引发的回调。
		/// </summary>
		/// <param name="d">引发事件的对象。</param>
		/// <param name="e">事件包含的参数。</param>
		private static void TextChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			// 代码段自动生成的局部变量。
			var target = (EditableComboBox)d;
			var oldValue = (string)e.OldValue;
			var newValue = (string)e.NewValue;

			if (oldValue != newValue)
			{
				target.SyncText();
			}
		}

		/// <summary>
		/// 获取或设置一个值，指示当用户进入输入框试图输入的时候，是否保持下拉菜单为打开状态。
		/// </summary>
		public bool StaysOpenOnEdit
		{
			get
			{
				return (bool)GetValue(StaysOpenOnEditProperty);
			}
			set
			{
				SetValue(StaysOpenOnEditProperty, value);
			}
		}

		/// <summary>
		/// 标识 <see cref="StaysOpenOnEdit" /> 依赖项属性。
		/// </summary>
		public static readonly DependencyProperty StaysOpenOnEditProperty = DependencyProperty.Register("StaysOpenOnEdit", typeof(bool), typeof(EditableComboBox), new PropertyMetadata(false, StaysOpenOnEditChangedCallback));

		/// <summary>
		/// 当 <see cref="StaysOpenOnEdit" /> 属性更改时引发的回调。
		/// </summary>
		/// <param name="d">引发事件的对象。</param>
		/// <param name="e">事件包含的参数。</param>
		private static void StaysOpenOnEditChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			// 代码段自动生成的局部变量。
			var target = (EditableComboBox)d;
			var oldValue = (bool)e.OldValue;
			var newValue = (bool)e.NewValue;

			// 焦点处理。
			if (oldValue != newValue)
			{
				if (FocusManager.GetFocusedElement(target) == target.EditTextBox)
				{
					target.NotifyTextBoxFocused();
				}
			}
		}

		#endregion

		#region 辅助样式属性

		/// <summary>
		/// 获取或设置编辑用文本框的样式。
		/// </summary>
		public Style EditTextBoxStyle
		{
			get
			{
				return (Style)GetValue(EditTextBoxStyleProperty);
			}
			set
			{
				SetValue(EditTextBoxStyleProperty, value);
			}
		}

		/// <summary>
		/// 标识 <see cref="EditTextBoxStyle" /> 依赖项属性。
		/// </summary>
		public static readonly DependencyProperty EditTextBoxStyleProperty = DependencyProperty.Register("EditTextBoxStyle", typeof(Style), typeof(EditableComboBox), new PropertyMetadata(null));

		#endregion

		#region 内部成员

		/// <summary>
		/// 获取编辑时显示的文本框。
		/// </summary>
		protected TextBox EditTextBox
		{
			get
			{
				return this.GetTemplateChild("EditTextBox") as TextBox;
			}
		}

		/// <summary>
		/// 获取非编辑时显示内容的占位符。
		/// </summary>
		protected ContentPresenter ContentPresenter
		{
			get
			{
				return this.GetTemplateChild("ContentPresenter") as ContentPresenter;
			}
		}

		#endregion

		#region 重写关键方法

		public override void OnApplyTemplate()
		{
			this.UnbindInternalEvents();

			base.OnApplyTemplate();

			this.BindInternalEvents();

			this.SyncIsEditable();
			this.SyncIsReadOnly();
			this.SyncText();

			this.CreateTextBinding();
		}

		/// <summary>
		/// 创建核心绑定。
		/// </summary>
		protected void CreateTextBinding()
		{
			if (this.EditTextBox != null)
			{
				var binding = new Binding
				{
					Source = this,
					Path = new PropertyPath("SelectedItem"),
					Mode = BindingMode.TwoWay
				};

				this.EditTextBox.SetBinding(TextBox.TextProperty, binding);
			}
		}

		/// <summary>
		/// 取消绑定内部事件。
		/// </summary>
		protected virtual void UnbindInternalEvents()
		{
			if (this.EditTextBox != null)
			{
				this.EditTextBox.TextChanged -= EditTextBox_TextChanged;
				this.EditTextBox.GotFocus -= EditTextBox_GotFocus;
			}
		}

		/// <summary>
		/// 绑定内部事件。
		/// </summary>
		protected virtual void BindInternalEvents()
		{
			if (this.EditTextBox != null)
			{
				this.EditTextBox.TextChanged += EditTextBox_TextChanged;
				this.EditTextBox.GotFocus += EditTextBox_GotFocus;
			}
		}

		void EditTextBox_GotFocus(object sender, RoutedEventArgs e)
		{
			this.NotifyTextBoxFocused();
		}


		void EditTextBox_TextChanged(object sender, TextChangedEventArgs e)
		{
			this.Text = this.EditTextBox.Text;
		}

		/// <summary>
		/// 当文本框接收到焦点时引发通知。
		/// </summary>
		protected void NotifyTextBoxFocused()
		{
			// 强制关闭列表。
			if (!this.StaysOpenOnEdit)
			{
				this.IsDropDownOpen = false;
			}
		}

		/// <summary>
		/// 同步文字。
		/// </summary>
		private void SyncText()
		{
			if (this.EditTextBox != null)
			{
				//this.EditTextBox.Text = this.Text ?? string.Empty;
			}
		}

		protected void SyncIsReadOnly()
		{
			if (this.EditTextBox != null)
			{
				this.EditTextBox.IsReadOnly = this.IsReadOnly;
			}
		}

		/// <summary>
		/// 将界面和 <see cref="IsEditable"/> 属性进行同步。
		/// </summary>
		protected void SyncIsEditable()
		{
			if (this.IsEditable)
			{
				if (this.EditTextBox != null)
				{
					this.EditTextBox.Visibility = Visibility.Visible;
				}

				if (this.ContentPresenter != null)
				{
					this.ContentPresenter.Visibility = Visibility.Collapsed;
				}
			}
			else
			{
				if (this.EditTextBox != null)
				{
					this.EditTextBox.Visibility = Visibility.Collapsed;
				}

				if (this.ContentPresenter != null)
				{
					this.ContentPresenter.Visibility = Visibility.Visible;
				}

			}
		}

		/// <summary>
		/// 根据选项更新文字。
		/// </summary>
		private void UpdateTextFromSelection()
		{
			if (this.SelectedIndex == -1)
			{
				this.Text = string.Empty;
			}
			else
			{
				this.Text = this.SelectedValue.ToString();
			}
		}

		protected override void OnDropDownClosed(EventArgs e)
		{
			base.OnDropDownClosed(e);
			this.UpdateTextFromSelection();
		}

		#endregion

		#region 动画处理

		/// <summary>
		/// 在编辑状态发生变化时引发动画。
		/// </summary>
		protected void UpdateEditState()
		{
			if (this.IsEditable)
			{
				VisualStateManager.GoToState(this, "Editable", true);
			}
			else
			{
				VisualStateManager.GoToState(this, "NonEditable", true);
			}
		}

		/// <summary>
		/// 在只读状态发生变化时引发动画。
		/// </summary>
		protected void UpdateReadState()
		{
			if (this.IsReadOnly)
			{
				VisualStateManager.GoToState(this, "ReadOnly", true);
			}
			else
			{
				VisualStateManager.GoToState(this, "NonReadOnly", true);
			}
		}

		#endregion

	}
}
